package db

import (
	"data-system/config"
	"data-system/models"
	"data-system/tools"
	"encoding/json"
	"fmt"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/dgraph-io/badger/v4"
)

const (
	NodeTypePrefix = "nt:"
	RealDataPrefix = "data:"
	ColumnPrefix   = "column:"
	IndexPrefix    = "index:"
)

type Ctx struct {
	Db    *badger.DB
	DbDir string
}

var DB *Ctx

func NewDB() *Ctx {
	dbDir := config.Cfg().DatabaseDir
	if DB != nil && strings.EqualFold(DB.DbDir, dbDir) {
		return DB
	}
	if DB != nil && !strings.EqualFold(DB.DbDir, dbDir) {
		DB.Db.Close()
	}
	db, err := badger.Open(badger.DefaultOptions(dbDir))
	if err != nil {
		log.Println("创建数据库连接失败：", err)
	}
	DB = &Ctx{
		Db:    db,
		DbDir: dbDir,
	}
	return DB
}

func (db *Ctx) BatchSave(nodes []models.NodeData) error {
	for _, node := range nodes {
		err := db.Save(node)
		if err != nil {
			return err
		}
	}
	return nil
}

func (db *Ctx) Save(node models.NodeData) error {
	writeBatch := db.Db.NewWriteBatch()
	defer writeBatch.Cancel()
	defer writeBatch.Flush()
	data := tools.ObjToJson(tools.ObjToMap(node))
	realDataKey := fmt.Sprintf(RealDataPrefix+"%v:%s", node.NodeType, node.Id)
	if err := writeBatch.Delete([]byte(realDataKey)); err != nil {
		log.Println(err)
		return err
	}
	if err := writeBatch.Set([]byte(realDataKey), []byte(data)); err != nil {
		log.Println(err)
		return err
	}
	return nil
}

func (db *Ctx) QueryAll(nodeType string) ([]models.NodeData, error) {
	nodes := make([]models.NodeData, 0)
	prefixKey := fmt.Sprintf(RealDataPrefix+"%v:", nodeType)
	prefix := []byte(prefixKey)
	_ = db.Db.View(func(txn *badger.Txn) error {
		it := txn.NewIterator(badger.DefaultIteratorOptions)
		defer it.Close()
		for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {
			item := it.Item()
			v, _ := item.ValueCopy(nil)
			var node models.NodeData
			err := json.Unmarshal(v, &node)
			if err != nil {
				log.Println("转换失败")
			}
			nodes = append(nodes, node)
		}
		return nil
	})
	return nodes, nil
}

func (db *Ctx) QueryById(nodeType string, id int64) (models.NodeData, error) {
	var node models.NodeData
	delDataKey := fmt.Sprintf(RealDataPrefix+"%v:%s", nodeType, id)
	prefix := []byte(delDataKey)
	_ = db.Db.View(func(txn *badger.Txn) error {
		it := txn.NewIterator(badger.DefaultIteratorOptions)
		defer it.Close()
		for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {
			item := it.Item()
			v, _ := item.ValueCopy(nil)
			err := json.Unmarshal(v, &node)
			if err != nil {
				log.Println("转换失败")
			}
		}
		return nil
	})
	return node, nil
}

func (db *Ctx) DeleteById(node models.NodeData) error {
	delDataKey := fmt.Sprintf(RealDataPrefix+"%v:%s", node.NodeType, node.Id)
	if err := db.Db.DropPrefix([]byte(delDataKey)); err != nil {
		log.Println(err)
		return err
	}
	return nil
}

func (db *Ctx) clearIndex(batch *badger.WriteBatch, prefixKey string, id int64) {
	prefix := []byte(prefixKey)
	_ = db.Db.View(func(txn *badger.Txn) error {
		it := txn.NewIterator(badger.DefaultIteratorOptions)
		defer it.Close()
		for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {
			item := it.Item()
			key := item.Key()
			value, err := item.ValueCopy(nil)
			if strings.EqualFold(string(id), string(value)) {
				err = batch.Delete(key)
			}
			if err != nil {
				log.Println("删除失败")
			}
		}
		return nil
	})
}

type tokenKind int

const (
	tkObj tokenKind = iota // 对象key
	tkIdx                  // 数组索引
)

type token struct {
	kind tokenKind
	key  string // tkObj 时使用
	idx  int    // tkIdx 时使用
}

// helper 函数
func contains(s, substr string) bool {
	return len(substr) == 0 || (len(s) >= len(substr) && (stringIndex(s, substr) != -1))
}

// 替代 strings.Index 避免额外 import
func stringIndex(s, substr string) int {
	for i := 0; i <= len(s)-len(substr); i++ {
		if s[i:i+len(substr)] == substr {
			return i
		}
	}
	return -1
}

// 替代 strings.IndexRune
func indexRune(s string, r rune) int {
	for i, c := range s {
		if c == r {
			return i
		}
	}
	return -1
}

func parsePath(path string) []token {
	var ts []token
	parts := strings.Split(path, ".")
	for _, seg := range parts {
		if seg == "" {
			continue
		}
		rest := seg
		for {
			br := strings.IndexByte(rest, '[')
			if br == -1 {
				// 没有更多的 [index]
				ts = append(ts, token{kind: tkObj, key: rest})
				break
			}
			// 前缀对象名
			if br > 0 {
				ts = append(ts, token{kind: tkObj, key: rest[:br]})
			}
			rest = rest[br:] // 以 '[' 开头
			// 找到 ']'
			end := strings.IndexByte(rest, ']')
			if end == -1 {
				// 非法，整体当作对象键兜底
				ts = append(ts, token{kind: tkObj, key: rest})
				break
			}
			num := rest[1:end]
			if num == "" {
				// 空索引兜底
				ts = append(ts, token{kind: tkObj, key: rest[:end+1]})
			} else {
				ix, _ := strconv.Atoi(num)
				ts = append(ts, token{kind: tkIdx, idx: ix})
			}
			rest = rest[end+1:]
			if rest == "" {
				break
			}
		}
	}
	return ts
}

// -------- 递归插入：沿 token 序列把 value 放到树上 --------
// 智能类型转换
func smartConvert(val string) interface{} {
	if val == "true" {
		return true
	}
	if val == "false" {
		return false
	}
	if i, err := strconv.ParseInt(val, 10, 64); err == nil {
		return i
	}
	if f, err := strconv.ParseFloat(val, 64); err == nil {
		return f
	}
	if t, err := time.Parse(time.RFC3339, val); err == nil {
		return t
	}
	return val
}

// insertAt 根据 tokens 把 val 插入到 curr（map 或 slice 或 nil）上，返回更新后的节点
func insertAt(curr interface{}, tokens []token, val interface{}) interface{} {
	if len(tokens) == 0 {
		return val
	}
	t := tokens[0]
	rest := tokens[1:]
	switch t.kind {
	case tkObj:
		// 需要一个 map[string]interface{}
		var m map[string]interface{}
		if curr == nil {
			m = make(map[string]interface{})
		} else if mm, ok := curr.(map[string]interface{}); ok {
			m = mm
		} else {
			// 冲突兜底：强制转成对象容器
			m = make(map[string]interface{})
		}
		child := m[t.key]
		m[t.key] = insertAt(child, rest, val)
		return m

	case tkIdx:
		// 需要一个 []interface{}
		var arr []interface{}
		if curr == nil {
			arr = make([]interface{}, 0)
		} else if aa, ok := curr.([]interface{}); ok {
			arr = aa
		} else {
			// 冲突兜底：强制转成数组容器
			arr = make([]interface{}, 0)
		}
		// 扩容
		for len(arr) <= t.idx {
			arr = append(arr, nil)
		}
		arr[t.idx] = insertAt(arr[t.idx], rest, val)
		return arr
	}
	return val
}

// -------- 对外入口：扁平 map[string]string -> 嵌套 map[string]interface{} --------
func unflatten(flat map[string]string) map[string]interface{} {
	var root interface{} = make(map[string]interface{})
	for k, v := range flat {
		ts := parsePath(k)
		root = insertAt(root, ts, v)
	}
	// 根本该是对象
	if m, ok := root.(map[string]interface{}); ok {
		return m
	}
	return map[string]interface{}{}
}

// ======================= 扁平化函数 =======================
func flatten(prefix string, value interface{}, flat map[string]interface{}) {
	switch v := value.(type) {
	case map[string]interface{}:
		for k, sub := range v {
			key := k
			if prefix != "" {
				key = prefix + "." + k
			}
			flatten(key, sub, flat)
		}
	case []interface{}:
		for i, sub := range v {
			key := fmt.Sprintf("%s[%d]", prefix, i)
			flatten(key, sub, flat)
		}
	case nil:
		flat[prefix] = "null"
	default:
		flat[prefix] = v
	}
}
